﻿using System;
using System.Diagnostics;

namespace CoCoonCoreWM6
{
    public class CPU
    {
        private short programCounter;

        private byte registerA;

        private byte registerB ;

        private short registerD ;

        private byte conditionCode ;

        private short pointerX;

        private short pointerY;

        private short systemStack;

        private short userStack;

        private byte directPage;

        public int ClockingSpeed;

        public CPU()
        {
            programCounter = 0;
            registerA = 0;
            registerB = 0;
            registerD = 0;
            conditionCode = 0;
            pointerX = 0;
            pointerY = 0;
            systemStack = 0;
            userStack = 0;
            directPage = 0;

            ClockingSpeed = 1; 
        }

        public int ExecuteCurrentInstruction()
        {
            int cycles = 0;
            short compare;
            short result;
            short offset;
            byte m;
            if (programCounter > RAM.Memory.Length) programCounter = 0;

            byte b = RAM.Memory[programCounter++];

            Debug.WriteLine(" * executing: " +  b + " (" + Convert.ToString(b, 16) + ") @ " + programCounter + "(" + Convert.ToString(programCounter, 16) + ")");
            
            #region instructions  

            switch (b)
            {
                #region 0x0

                case 0x00:
                    //NEG         Direct    
                    // uaaaa 

                    break;

                case 0x01:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x02:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x03:
                    //COM         Direct    
                    // -aa01 

                    break;

                case 0x04:
                    //LSR         Direct    
                    // -0a-s 

                    break;

                case 0x05:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x06:
                    //ROR         Direct    
                    // -aa-s 

                    break;

                case 0x07:
                    //ASR         Direct    
                    // uaa-s 

                    break;

                case 0x08:
                    //LSL/ASL     Direct    
                    // naaas 

                    break;

                case 0x09:
                    //ROL         Direct    
                    // -aaas 

                    break;

                case 0x0A:
                    //DEC         Direct    
                    // -aaa- 

                    break;

                case 0x0B:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x0C:
                    //INC         Direct    
                    // -aaa- 

                    break;

                case 0x0D:
                    //TST         Direct    
                    // -aa0- 

                    break;

                case 0x0E:
                    //JMP         Direct    
                    // ----- 

                    break;

                case 0x0F:
                    //CLR         Direct    
                    // -0100 

                    break;

                    #endregion

                #region 0x10

                case 0x10:
                    //PAGE1+      Variant   
                    // +++++ 

                    m = RAM.Memory[++programCounter];

                    switch (m)
                    {
                        case 0x8C:
                            //CMPY        Immediate 
                            compare = (short)((RAM.Memory[programCounter++] * 256) + RAM.Memory[programCounter++]);
                            result = (short)(pointerY - compare);
                            
                            // -aaaa 
                            SetConditionCode(null,
                                             ((short)(result & 0x8000) == -32768),
                                             (result == 0),
                                             (result >> 16 == -1),  //TODO: overflow ?
                                             ((result & 0x10000) == 65536)); //TODO: carry ?
                            cycles = 4;
                            break;

                        case 0x8E:
                            //LDY          Immediate
                            pointerY = (short)
                                ((RAM.Memory[programCounter++] * 256)
                                + RAM.Memory[programCounter++]);
                            // -aa0- 
                            SetConditionCode(null, (pointerX > 0x8000), pointerX != 0, false, null);
                            cycles = 4;
                            break;

                        default:

                            break;
                    }

                    break;

                #endregion
                    
                #region 0x11

                case 0x11:
                    //PAGE2+      Variant   
                    // +++++ 

                    break;

                #endregion
                    
                #region 0x1

                case 0x12:
                    //NOP         Inherent  
                    //TODO do nothing (delay 2 cycles) 
                    // ----- 
                    cycles = 1;
                    break;

                case 0x13:
                    //SYNC        Inherent  
                    // ----- 

                    break;

                case 0x14:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x15:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x16:
                    //LBRA        Relative  
                    // ----- 

                    break;

                case 0x17:
                    //LBSR        Relative  
                    // ----- 

                    break;

                case 0x18:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x19:
                    //DAA         Inherent  
                    // -aa0a 

                    break;

                case 0x1A:
                    //ORCC        Immediate 
                    // ddddd 

                    break;

                case 0x1B:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x1C:
                    //ANDCC       Immediate 
                    // ddddd 

                    break;

                case 0x1D:
                    //SEX         Inherent  
                    // -aa0- 

                    break;

                case 0x1E:
                    //EXG         Inherent  
                    // ccccc 

                    break;

                case 0x1F:
                    //TFR         Inherent  
                    // ccccc 

                    break;

                    #endregion

                #region 0x2

                case 0x20:
                    //BRA         Relative  
                    BranchRelative();
                    cycles = 2;
                    // ----- 
                    break;

                case 0x21:
                    //BRN         Relative  
                    // ----- 
                    cycles = 2;

                    break;

                case 0x22:
                    //BHI         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x23:
                    //BLS         Relative
                    if ((conditionCode & 0x04) == 0x04 || (conditionCode & 0x01) == 0x01)
                    {
                        BranchRelative();
                    }
                    // ----- 
                    cycles = 2;
                    break;

                case 0x24:
                    //BHS/BCC     Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x25:
                    //BLO/BCS     Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x26:
                    //BNE         Relative  
                    if ((conditionCode & 0x04) == 0x04)
                        BranchRelative();
                    //    programCounter = (short)
                    //        (((short)(programCounter >> 8) << 8) |
                    //        ((byte)programCounter) + RAM.Memory[programCounter + 1]);
                    // ----- 
                    cycles = 2;
                    break;

                case 0x27:
                    //BEQ         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x28:
                    //BVC         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x29:
                    //BVS         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x2A:
                    //BPL         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x2B:
                    //BMI         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x2C:
                    //BGE         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x2D:
                    //BLT         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x2E:
                    //BGT         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                case 0x2F:
                    //BLE         Relative  
                    // ----- 
                    cycles = 2;
                    break;

                    #endregion

                #region 0x3

                case 0x30:
                    //LEAX        Indexed   
                    // --a-- 

                    break;

                case 0x31:
                    //LEAY        Indexed   
                    // --a-- 
                    DoIndexedPostByte(RAM.Memory[programCounter++]);
                    SetConditionCode(null, null, (pointerY == 0), null, null);
                    cycles = 4;
                    break;

                case 0x32:
                    //LEAS        Indexed   
                    // ----- 

                    break;

                case 0x33:
                    //LEAU        Indexed   
                    // ----- 

                    break;

                case 0x34:
                    //PSHS        Inherent  
                    // ----- 

                    break;

                case 0x35:
                    //PULS        Inherent  
                    // ccccc 

                    break;

                case 0x36:
                    //PSHU        Inherent  
                    // ----- 

                    break;

                case 0x37:
                    //PULU        Inherent  
                    // ccccc 

                    break;

                case 0x38:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x39:
                    //RTS         Inherent  
                    // ----- 

                    break;

                case 0x3A:
                    //ABX         Inherent  
                    // ----- 

                    break;

                case 0x3B:
                    //RTI         Inherent  
                    // ----- 

                    break;

                case 0x3C:
                    //CWAI        Inherent  
                    // ddddd 

                    break;

                case 0x3D:
                    //MUL         Inherent  
                    // --a-a 

                    break;

                case 0x3E:
                    //RESET*      Inherent  
                    // 

                    break;

                case 0x3F:
                    //SWI         Inherent  
                    // ----- 


                    break;

                #endregion

                #region 0x4

                case 0x40:
                    //NEGA        Inherent  
                    // uaaaa 

                    break;

                case 0x41:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x42:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x43:
                    //COMA        Inherent  
                    // -aa01 

                    break;

                case 0x44:
                    //LSRA        Inherent  
                    // -0a-s 

                    break;

                case 0x45:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x46:
                    //RORA        Inherent  
                    // -aa-s 

                    break;

                case 0x47:
                    //ASRA        Inherent  
                    // uaa-s 

                    break;

                case 0x48:
                    //LSLA/ASLA   Inherent  
                    // naaas 

                    break;

                case 0x49:
                    //ROLA        Inherent  
                    // -aaas 

                    break;

                case 0x4A:
                    //DECA        Inherent  
                    registerA--;
                    // -aaa- 
                    SetConditionCode(null, 
                        registerA > 128, 
                        registerA == 0, 
                        registerA == 0x7F, null);
                    cycles = 2;
                    break;

                case 0x4B:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x4C:
                    //INCA        Inherent  
                    // -aaa- 

                    break;

                case 0x4D:
                    //TSTA        Inherent  
                    // -aa0- 

                    break;

                case 0x4E:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x4F:
                    //CLRA        Inherent  
                    // -0100 

                    break;


                    #endregion

                #region 0x5

                case 0x50:
                    //NEGB        Inherent  
                    // uaaaa 

                    break;

                case 0x51:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x52:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x53:
                    //COMB        Inherent  
                    // -aa01 

                    break;

                case 0x54:
                    //LSRB        Inherent  
                    // -0a-s 

                    break;

                case 0x55:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x56:
                    //RORB        Inherent  
                    // -aa-s 

                    break;

                case 0x57:
                    //ASRB        Inherent  
                    // uaa-s 

                    break;

                case 0x58:
                    //LSLB/ASLB   Inherent  
                    // naaas 

                    break;

                case 0x59:
                    //ROLB        Inherent  
                    // -aaas 

                    break;

                case 0x5A:
                    //DECB        Inherent  
                    registerB--;
                    // -aaa- 
                    SetConditionCode(null,
                        registerB > 128,
                        registerB == 0,
                        registerB == 0x7F, null);
                    cycles = 2;
                    break;

                case 0x5B:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x5C:
                    //INCB        Inherent  
                    // -aaa- 

                    break;

                case 0x5D:
                    //TSTB        Inherent  
                    // -aa0- 

                    break;

                case 0x5E:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x5F:
                    //CLRB        Inherent  
                    // -0100 

                    break;


                    #endregion

                #region 0x6

                case 0x60:
                    //NEG         Indexed   
                    // uaaaa 

                    break;

                case 0x61:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x62:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x63:
                    //COM         Indexed   
                    // -aa01 

                    break;

                case 0x64:
                    //LSR         Indexed   
                    // -0a-s 

                    break;

                case 0x65:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x66:
                    //ROR         Indexed   
                    // -aa-s 

                    break;

                case 0x67:
                    //ASR         Indexed   
                    // uaa-s 

                    break;

                case 0x68:
                    //LSL/ASL     Indexed   
                    // naaas 

                    break;

                case 0x69:
                    //ROL         Indexed   
                    // -aaas 

                    break;

                case 0x6A:
                    //DEC         Indexed   
                    // -aaa- 

                    break;

                case 0x6B:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x6C:
                    //INC         Indexed   
                    // -aaa- 

                    break;

                case 0x6D:
                    //TST         Indexed   
                    // -aa0- 

                    break;

                case 0x6E:
                    //JMP         Indexed   
                    // ----- 

                    break;

                case 0x6F:
                    //CLR         Indexed   
                    // -0100 

                    break;


                    #endregion

                #region 0x7

                case 0x70:
                    //NEG         Extended  
                    // uaaaa 

                    break;

                case 0x71:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x72:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x73:
                    //COM         Extended  
                    // -aa01 

                    break;

                case 0x74:
                    //LSR         Extended  
                    // -0a-s 

                    break;

                case 0x75:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x76:
                    //ROR         Extended  
                    // -aa-s 

                    break;

                case 0x77:
                    //ASR         Extended  
                    // uaa-s 

                    break;

                case 0x78:
                    //LSL/ASL     Extended  
                    // naaas 

                    break;

                case 0x79:
                    //ROL         Extended  
                    // -aaas 

                    break;

                case 0x7A:
                    //DEC         Extended  
                    m = --RAM.Memory[GetAddressExtended()];
                    SetConditionCode(null, m < 0, m == 0, m == 0x7F, null);
                    // -aaa- 
                    cycles = 2;
                    break;

                case 0x7B:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x7C:
                    //INC         Extended  
                    // -aaa- 

                    break;

                case 0x7D:
                    //TST         Extended  
                    // -aa0- 

                    break;

                case 0x7E:
                    //JMP         Extended  
                    // ----- 

                    break;

                case 0x7F:
                    //CLR         Extended  
                    // -0100 

                    break;


                    #endregion

                #region 0x8

                case 0x80:
                    //SUBA        Immediate 
                    // uaaaa 

                    break;

                case 0x81:
                    //CMPA        Immediate 
                    // uaaaa 

                    break;

                case 0x82:
                    //SBCA        Immediate 
                    // uaaaa 

                    break;

                case 0x83:
                    //SUBD        Immediate 
                    // -aaaa 

                    break;

                case 0x84:
                    //ANDA        Immediate 
                    // -aa0- 

                    break;

                case 0x85:
                    //BITA        Immediate 
                    // -aa0- 

                    break;

                case 0x86:
                    //LDA         Immediate 
                    registerA = RAM.Memory[programCounter++];                  
                    // -aa0- 
                    SetConditionCode(null, (registerA > 0x80), registerA != 0, false, null);
                    cycles = 2;
                    break;

                case 0x87:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0x88:
                    //EORA        Immediate 
                    // -aa0- 

                    break;

                case 0x89:
                    //ADCA        Immediate 
                    // aaaaa 

                    break;

                case 0x8A:
                    //ORA         Immediate 
                    // -aa0- 

                    break;

                case 0x8B:
                    //ADDA        Immediate 
                    // aaaaa 

                    break;

                case 0x8C:
                    //CMPX        Immediate 
                    compare = (short) ((RAM.Memory[programCounter++]*256) + RAM.Memory[programCounter++]);
                    result = (short) (pointerX - compare);
                    
                    // -aaaa 
                    SetConditionCode(null,
                                     ((short)(result & 0x8000) == -32768), 
                                     (result == 0),
                                     (result >> 16 == -1),  //TODO: overflow ?
                                     ((result & 0x10000) == 65536)); //TODO: carry ?
                    cycles = 2;
                    break;

                case 0x8D:
                    //BSR         Relative  
                    // ----- 

                    break;

                case 0x8E:
                    //LDX         Immediate
                    pointerX = (short) 
                        ((RAM.Memory[programCounter++]*256)
                        + RAM.Memory[programCounter++]) ;             
                    // -aa0- 
                    SetConditionCode(null, (pointerX > 0x8000), pointerX != 0, false, null);
                    cycles = 4;
                    break;

                case 0x8F:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;


                    #endregion

                #region 0x9

                case 0x90:
                    //SUBA        Direct    
                    // uaaaa 

                    break;

                case 0x91:
                    //CMPA        Direct    
                    // uaaaa 

                    break;

                case 0x92:
                    //SBCA        Direct    
                    // uaaaa 

                    break;

                case 0x93:
                    //SUBD        Direct    
                    // -aaaa 

                    break;

                case 0x94:
                    //ANDA        Direct    
                    // -aa0- 

                    break;

                case 0x95:
                    //BITA        Direct    
                    // -aa0- 

                    break;

                case 0x96:
                    //LDA         Direct    
                    // -aa0- 

                    break;

                case 0x97:
                    //STA         Direct    
                    RAM.Memory[(short) (directPage*256) + programCounter++] = registerA;
                    // -aa0- 
                    SetConditionCode(null, (registerA > 128), registerA == 0, false, null);
                    cycles = 2;
                    break;

                case 0x98:
                    //EORA        Direct    
                    // -aa0- 

                    break;

                case 0x99:
                    //ADCA        Direct    
                    // aaaaa 

                    break;

                case 0x9A:
                    //ORA         Direct    
                    // -aa0- 

                    break;

                case 0x9B:
                    //ADDA        Direct    
                    // aaaaa 

                    break;

                case 0x9C:
                    //CMPX        Direct    
                    // -aaaa 

                    break;

                case 0x9D:
                    //JSR         Direct    
                    // ----- 

                    break;

                case 0x9E:
                    //LDX         Direct    
                    // -aa0- 

                    break;

                case 0x9F:
                    //STX         Direct    
                    // -aa0- 

                    break;


                    #endregion

                #region 0xA

                case 0xA0:
                    //SUBA        Indexed   
                    // uaaaa 

                    break;

                case 0xA1:
                    //CMPA        Indexed   
                    // uaaaa 

                    break;

                case 0xA2:
                    //SBCA        Indexed   
                    // uaaaa 

                    break;

                case 0xA3:
                    //SUBD        Indexed   
                    // -aaaa 

                    break;

                case 0xA4:
                    //ANDA        Indexed   
                    // -aa0- 

                    break;

                case 0xA5:
                    //BITA        Indexed   
                    // -aa0- 

                    break;

                case 0xA6:
                    //LDA         Indexed   
                    // -aa0- 

                    break;

                case 0xA7:
                    //STA         Indexed   
                    offset = DoIndexedPostByte(RAM.Memory[programCounter++]);
                    RAM.Memory[offset] = (registerA);
                    // -aa0- 
                    SetConditionCode(null, (registerA > 128), registerA == 0, false, null);
                    cycles = 2;
                    break;

                case 0xA8:
                    //EORA        Indexed   
                    // -aa0- 

                    break;

                case 0xA9:
                    //ADCA        Indexed   
                    // aaaaa 

                    break;

                case 0xAA:
                    //ORA         Indexed   
                    // -aa0- 

                    break;

                case 0xAB:
                    //ADDA        Indexed   
                    // aaaaa 

                    break;

                case 0xAC:
                    //CMPX        Indexed   
                    // -aaaa 

                    break;

                case 0xAD:
                    //JSR         Indexed   
                    // ----- 

                    break;

                case 0xAE:
                    //LDX         Indexed   
                    // -aa0- 

                    break;

                case 0xAF:
                    //STX         Indexed   
                    // -aa0- 

                    break;


                    #endregion

                #region 0xB

                case 0xB0:
                    //SUBA        Extended  
                    // uaaaa 

                    break;

                case 0xB1:
                    //CMPA        Extended  
                    // uaaaa 

                    break;

                case 0xB2:
                    //SBCA        Extended  
                    // uaaaa 

                    break;

                case 0xB3:
                    //SUBD        Extended  
                    // -aaaa 

                    break;

                case 0xB4:
                    //ANDA        Extended  
                    // -aa0- 

                    break;

                case 0xB5:
                    //BITA        Extended  
                    // -aa0- 

                    break;

                case 0xB6:
                    //LDA         Extended  
                    registerA = RAM.Memory[GetAddressExtended()];
                    // -aa0- 
                    SetConditionCode(null, (registerA > 128), registerA == 0, false, null);
                    cycles = 4;
                    break;

                case 0xB7:
                    //STA         Extended  
                    RAM.Memory[GetAddressExtended()] = registerA;
                    // -aa0- 
                    SetConditionCode(null, (registerA > 128), registerA == 0, false, null);
                    cycles = 4;
                    break;

                case 0xB8:
                    //EORA        Extended  
                    // -aa0- 

                    break;

                case 0xB9:
                    //ADCA        Extended  
                    // aaaaa 

                    break;

                case 0xBA:
                    //ORA         Extended  
                    // -aa0- 

                    break;

                case 0xBB:
                    //ADDA        Extended  
                    // aaaaa 

                    break;

                case 0xBC:
                    //CMPX        Extended  
                    // -aaaa 

                    break;

                case 0xBD:
                    //JSR         Extended  
                    // ----- 

                    break;

                case 0xBE:
                    //LDX         Extended  
                    // -aa0- 

                    break;

                case 0xBF:
                    //STX         Extended  
                    // -aa0- 

                    break;


                    #endregion

                #region 0xC

                case 0xC0:
                    //SUBB        Immediate 
                    // uaaaa 

                    break;

                case 0xC1:
                    //CMPB        Immediate 
                    // uaaaa 

                    break;

                case 0xC2:
                    //SBCB        Immediate 
                    // uaaaa 

                    break;

                case 0xC3:
                    //ADDD        Immediate 
                    // -aaaa 

                    break;

                case 0xC4:
                    //ANDB        Immediate 
                    // -aa0- 

                    break;

                case 0xC5:
                    //BITB        Immediate 
                    // -aa0- 

                    break;

                case 0xC6:
                    //LDB         Immediate 
                    registerB = RAM.Memory[programCounter++];
                    // -aa0- 
                    SetConditionCode(null, (registerB > 0x80), registerB != 0, false, null);
                    cycles = 2;
                    break;

                case 0xC7:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0xC8:
                    //EORB        Immediate 
                    // -aa0- 

                    break;

                case 0xC9:
                    //ADCB        Immediate 
                    // aaaaa 

                    break;

                case 0xCA:
                    //ORB         Immediate 
                    // -aa0- 

                    break;

                case 0xCB:
                    //ADDB        Immediate 
                    // aaaaa 

                    break;

                case 0xCC:
                    //LDD         Immediate 
                    registerD = (short)
                        ((RAM.Memory[programCounter++] * 256)
                        + RAM.Memory[programCounter++]);
                    // -aa0- 
                    SetConditionCode(null, (registerD > 0x8000), registerD != 0, false, null);
                    cycles = 2;
                    break;

                case 0xCD:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;

                case 0xCE:
                    //LDU         Immediate 
                    // -aa0- 

                    break;

                case 0xCF:
                    //ILLEGAL     Illegal   
                    // uuuuu 

                    break;


                    #endregion

                #region 0xD

                case 0xD0:
                    //SUBB        Direct    
                    // uaaaa 

                    break;

                case 0xD1:
                    //CMPB        Direct    
                    // uaaaa 

                    break;

                case 0xD2:
                    //SBCB        Direct    
                    // uaaaa 

                    break;

                case 0xD3:
                    //ADDD        Direct    
                    // -aaaa 

                    break;

                case 0xD4:
                    //ANDB        Direct    
                    // -aa0- 

                    break;

                case 0xD5:
                    //BITB        Direct    
                    // -aa0- 

                    break;

                case 0xD6:
                    //LDB         Direct    
                    // -aa0- 

                    break;

                case 0xD7:
                    //STB         Direct    
                    // -aa0- 

                    break;

                case 0xD8:
                    //EORB        Direct    
                    // -aa0- 

                    break;

                case 0xD9:
                    //ADCB        Direct    
                    // aaaaa 

                    break;

                case 0xDA:
                    //ORB         Direct    
                    // -aa0- 

                    break;

                case 0xDB:
                    //ADDB        Direct    
                    // aaaaa 

                    break;

                case 0xDC:
                    //LDD         Direct    
                    // -aa0- 

                    break;

                case 0xDD:
                    //STD         Direct    
                    
                    // -aa0- 

                    break;

                case 0xDE:
                    //LDU         Direct    
                    // -aa0- 

                    break;

                case 0xDF:
                    //STU         Direct    
                    // -aa0- 

                    break;

                    #endregion

                #region 0xE

                case 0xE0:
                    //SUBB        Indexed   
                    // uaaaa 

                    break;

                case 0xE1:
                    //CMPB        Indexed   
                    // uaaaa 

                    break;

                case 0xE2:
                    //SBCB        Indexed   
                    // uaaaa 

                    break;

                case 0xE3:
                    //ADDD        Indexed   
                    // -aaaa 

                    break;

                case 0xE4:
                    //ANDB        Indexed   
                    // -aa0- 

                    break;

                case 0xE5:
                    //BITB        Indexed   
                    // -aa0- 

                    break;

                case 0xE6:
                    //LDB         Indexed   
                    // -aa0- 

                    break;

                case 0xE7:
                    //STB         Indexed   
                    // -aa0- 

                    break;

                case 0xE8:
                    //EORB        Indexed   
                    // -aa0- 

                    break;

                case 0xE9:
                    //ADCB        Indexed   
                    // aaaaa 

                    break;

                case 0xEA:
                    //ORB         Indexed   
                    // -aa0- 

                    break;

                case 0xEB:
                    //ADDB        Indexed   
                    // aaaaa 

                    break;

                case 0xEC:
                    //LDD         Indexed   
                    // -aa0- 

                    break;

                case 0xED:
                    //STD         Indexed   
                    offset = DoIndexedPostByte(RAM.Memory[programCounter++]);
                    RAM.Memory[offset++] = (byte) (registerD >> 8); 
                    RAM.Memory[offset] = (byte)(registerD);
                    // -aa0- 
                    SetConditionCode(null, (registerD > 0x8000), registerD != 0, false, null);
                    cycles = 4;
                    break;

                case 0xEE:
                    //LDU         Indexed   
                    // -aa0- 

                    break;

                case 0xEF:
                    //STU         Indexed   
                    // -aa0- 

                    break;

                    #endregion

                #region 0xF 

                case 0xF0:
                    //SUBB        Extended  
                    // uaaaa 

                    break;

                case 0xF1:
                    //CMPB        Extended  
                    // uaaaa 

                    break;

                case 0xF2:
                    //SBCB        Extended  
                    // uaaaa 

                    break;

                case 0xF3:
                    //ADDD        Extended  
                    // -aaaa 

                    break;

                case 0xF4:
                    //ANDB        Extended  
                    // -aa0- 

                    break;

                case 0xF5:
                    //BITB        Extended  
                    // -aa0- 

                    break;

                case 0xF6:
                    //LDB         Extended  
                    // -aa0- 

                    break;

                case 0xF7:
                    //STB         Extended  
                    // -aa0- 

                    break;

                case 0xF8:
                    //EORB        Extended  
                    // -aa0- 

                    break;

                case 0xF9:
                    //ADCB        Extended  
                    // aaaaa 

                    break;

                case 0xFA:
                    //ORB         Extended  
                    // -aa0- 

                    break;

                case 0xFB:
                    //ADDB        Extended  
                    // aaaaa 

                    break;

                case 0xFC:
                    //LDD         Extended  
                    // -aa0- 

                    break;

                case 0xFD:
                    //STD         Extended  
                    // -aa0- 

                    break;

                case 0xFE:
                    //LDU         Extended  
                    // -aa0- 

                    break;

                case 0xFF:
                    //STU         Extended  
                    // -aa0- 

                    break;

                    #endregion
                
                default:


                    break;

            }
            #endregion

            return cycles;
        }

        private void BranchRelative()
        {
            byte bra = RAM.Memory[programCounter];
            short pos = programCounter;
            short newpos = (short)((((short)(pos >> 8) << 8) | (byte)((byte)pos + bra)) + 1);
            programCounter = newpos;
        }

        private short DoIndexedPostByte(byte p)
        {
            #region analyze postbyte

            //bit 7: 5 bit offset or not
            bool not5bitoffset = ((p & 0x7F)) == 0;
            //bits 6-5: register (00: X, 01: Y, 10: U, 11: S)
            int registerIndex = p & 0x9F >> 5;
            //bit 4: indirect? (0=direct, 1= indirect) 
            bool indirect = (p & 0xEF >> 4) == 1;
            //   OR: sign with 5-bit offset (0 = positive; 1 = negative)
            bool offsetSign = indirect;
            //bits 3-0: addressíng mode (0000 = 0; 0001 = 1; 0010 = 2; 0011 = 3; 0100 = 4; 0101 = 5; 0110 = 6; 1000 = 8; 1001 = 9; 1011 = B ; 1100 = C; 1101 = D; 1111 = F)
            int addressingMode = p & 0x0F;
            //   OR: unsigned offset with 5-bit offset 
            int offset = addressingMode;

            #endregion

            short currentRegisterValue = 0;
            short effectOnRegisterValue = 0;
            
            if (!not5bitoffset)
            {
                #region register used

                switch (registerIndex)
                {
                    case 0:
                        currentRegisterValue = pointerX;
                        break;

                    case 1:
                        currentRegisterValue = pointerY;
                        break;

                    case 2:
                        currentRegisterValue = userStack;
                        break;

                    case 3:
                        currentRegisterValue = systemStack;
                        break;
                }

                #endregion

                short returnValue = 0;

                #region addressing mode used 

                switch (addressingMode)
                {
                        // 0000: autoincrement by 1
                    case 0x00:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = +1;
                        break;

                        // 0001: autoincrement by 2
                    case 0x01:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = +2;
                        break;

                        // 0010: autodecrement by 1
                    case 0x02:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = -1;
                        break;

                        // 0011: autodecrement by 2
                    case 0x03:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = -2;
                        break;

                        // 0100: zero offset
                    case 0x04:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = 0;
                        break;

                        // 0101: register B offset
                    case 0x05:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = (short)(currentRegisterValue + registerB);
                        break;

                        // 0110: register A offset
                    case 0x06:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = (short)(currentRegisterValue
                                                        + registerA);
                        break;

                        // 1000: 8 bit offset
                    case 0x08:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = (short)(currentRegisterValue
                                                        + RAM.Memory[programCounter++]);
                        break;

                        // 1001: 16 bit offset
                    case 0x09:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = (short)(currentRegisterValue
                                                        + (RAM.Memory[programCounter++] * 256
                                                           + RAM.Memory[programCounter++]));
                        break;

                        // 1011: register D offset
                    case 0x0B:
                        returnValue = currentRegisterValue;
                        effectOnRegisterValue = (short)(currentRegisterValue
                                                        + registerD);
                        break;

                        // 1100: PC 8 bit offset
                    case 0x0C:
                        returnValue = currentRegisterValue;
                        //TODO
                        break;

                        // 1101: PC 16 bit offset
                    case 0x0D:
                        returnValue = currentRegisterValue;
                        //TODO
                        break;

                        // 1111: Extended indirect 
                    case 0x0F:
                        returnValue = currentRegisterValue;
                        //TODO
                        break;
                }

                #endregion

                AdjustPointer(registerIndex, effectOnRegisterValue);

                return returnValue;
            }
            
            //5 bit offset 
            if (offsetSign) offset = 0 - ((((byte)(~offset)) & 0x0F) + 1);

            return AdjustPointer(registerIndex, offset);
        }

        private short AdjustPointer(int registerIndex, int offset)
        {
            switch (registerIndex)
            {
                case 0:
                    pointerX = (short)(pointerX + offset);
                    return pointerX;

                case 1:
                    pointerY = (short)(pointerY + offset);
                    return pointerY;

                case 2:
                    userStack = (short)(userStack + offset);
                    return userStack;

                case 3:
                    systemStack = (short)(systemStack + offset);
                    return systemStack;

                default:
                    return 0;
            }
        }

        private int GetAddressExtended()
        {
            byte msb = RAM.Memory[RAM.Memory[programCounter++]];
            byte lsb = RAM.Memory[RAM.Memory[programCounter++]];
            int address = msb * 256 + lsb;
            return address;
        }

        private void SetConditionCode(bool? I, bool? N, bool? Z, bool? V, bool? C)
        {
            SetConditionCode(null, null, null, I, N, Z, V, C);
        }

        private void SetConditionCode(bool? E, bool? F, bool? H, bool? I, bool? N, bool? Z, bool? V, bool? C)
        {
            if (E != null) conditionCode = (byte) ((bool) E ? (conditionCode | 0x80) : (conditionCode & 0x7F));
            if (F != null) conditionCode = (byte) ((bool) F ? (conditionCode | 0x40) : (conditionCode & 0xBF));
            if (H != null) conditionCode = (byte) ((bool) H ? (conditionCode | 0x20) : (conditionCode & 0xDF));
            if (I != null) conditionCode = (byte) ((bool) I ? (conditionCode | 0x10) : (conditionCode & 0xEF));
            
            if (N != null) conditionCode = (byte) ((bool) N ? (conditionCode | 0x08) : (conditionCode & 0xF7));
            if (Z != null) conditionCode = (byte) ((bool) Z ? (conditionCode | 0x04) : (conditionCode & 0xFB));
            if (V != null) conditionCode = (byte) ((bool) V ? (conditionCode | 0x02) : (conditionCode & 0xFD));
            if (C != null) conditionCode = (byte) ((bool) C ? (conditionCode | 0x01) : (conditionCode & 0xFE));
        }
    }
}

/*
Sample code
 
 * 

PCLS    LDX     #VIDRAM                  * 8E 04 00       * point to screen start
        LDD     #M0000                   * CC 00 00       * load empty word
Z279F   STD     ,X++                     * ED 81          * clear screen
        CMPX    #M1BFE                   * 8C 1B FE       * check for end
        BLS     Z279F                    * 23 F9          * loop until done (-7) 
LOOP    NOP                              * 12             * do nothing 
        BRA     LOOP                     * 20 FD          * loop like forever (-3) 
 * 



*/